//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
//
// (C) Copyright 2006 Marvell International Ltd.
// All Rights Reserved
//
/******************************************************************************
**
**  COPYRIGHT (C) 2001, 2002 Intel Corporation.
**
**  This software as well as the software described in it is furnished under
**  license and may only be used or copied in accordance with the terms of the
**  license. The information in this file is furnished for informational use
**  only, is subject to change without notice, and should not be construed as
**  a commitment by Intel Corporation. Intel Corporation assumes no
**  responsibility or liability for any errors or inaccuracies that may appear
**  in this document or any software that may be provided in association with
**  this document. 
**  Except as permitted by such license, no part of this document may be 
**  reproduced, stored in a retrieval system, or transmitted in any form or by
**  any means without the express written consent of Intel Corporation. 
**
**  FILENAME:       dma.c
**
**  PURPOSE: Contains all primitive functions for DMA Controller Engine 
**           access and control
**                  
******************************************************************************/

#include <windows.h>
#include <string.h>
#include <stdio.h>
#include <tchar.h>
#include <ceddk.h>

#include "monahans.h"

#include "xllp_dmac.h"
#include "dmawince.h"

extern volatile DMA_GLOBALS* pDMAGlobals;
extern volatile P_XLLP_DMAC_T	pDmacHandle;
//******************************************************************************
//
// Function Name: XllpDmacHwInit
//
// Description: Function called to initialize the DMAC hardware to default state   
//              Clears the DCSR and all channel to device mapping  			   
//  
// Input Arguments:
//	
//	                 
// Output Arguments:
//  	
//
// Return Value: 
//
// Notes:
//
//*******************************************************************************
// pkdebug ?? Function not needed.
/***
VOID XllpDmacHwInit(void)
{
    XLLP_UINT32_T		i;

	//
    // clear all of the DMA CSR registers
	//
    for (i=0; i < XLLP_DMAC_CHANNEL_NUM; i++)
    {
        //
        // Do it twice in case there are certain sticky bits...
	    //  
        pDmacHandle->DCSR[i] = 0x0;
	    pDmacHandle->DCSR[i] = 0x0;
    }
    
	//
	// Clear the alignment register
    // Clear the interrupt register
	//
	pDmacHandle->DALGN = 0x0;
    pDmacHandle->DINT  = 0x0;
    
	//
    // clear the DMA Request to Channel Map Registers
	//
    for (i=0; i < XLLP_DMAC_DRCMR1_NUM; i++)
    {
        pDmacHandle->DRCMR1[i] = 0x0;
    }

	for (i=0; i < XLLP_DMAC_DRCMR2_NUM; i++)
    {
        pDmacHandle->DRCMR2[i] = 0x0;
    }
    
	//
    // clear the descriptor registers
    //
    for(i=0; i < XLLP_DMAC_CHANNEL_NUM; i++)
    {
        //pDmacHandle->DDG[i].DDADR = 0x0;
        pDmacHandle->DDG[i].DSADR = 0x0;
        pDmacHandle->DDG[i].DTADR = 0x0;
        pDmacHandle->DDG[i].DCMD  = 0x0;
    }
	
}
***/


//******************************************************************************
//
// Function Name: XllpDmacRegisterDeviceHandler
//
// Description: Function called to register a handler that will be called for handling
//              interrupts related to this DMA channel.
//  			   
//  
// Input Arguments:
//		XLLP_UINT32_T		dmaChannel:     DMA channel
//      DeviceDmaIntHandler	dmaIntHandler:  Handler function
//	    void*				userContext:    User context to be passed back to handler
//	                 
// Output Arguments:
//  	
//
// Return Value: 
//	XLLP_ERR_BAD_CHANNEL:           When user passes an invalid DMA channel
//  XLLP_ERR_CHANNEL_NOT_ALLOCATED: When specified DMA chanel has not been allocated
//  XLLP_STATUS_SUCCESS:                  On success
//
// Notes:
//      Only one handler can be registered per DMA channel.
//      Should we be registering handlers or setting events ?
//      
//
//*******************************************************************************
// pkdebug ?? Function not needed.
/***
XLLP_STATUS_T	XllpDmacRegisterDeviceHandler
(
	XLLP_DMAC_CHANNEL_T	dmaChannel,
	DeviceDmaIntHandler	dmaIntHandler,
	void*				userContext
)
{
    if(dmaChannel > XLLP_DMAC_CHANNEL_NUM)
	    return XLLP_ERR_BAD_CHANNEL;

	//
    //  Channel should be allocated before registering a handler
	//
    if (!pDMAGlobals->pArrayChannel[dmaChannel] )
        return XLLP_ERR_CHANNEL_NOT_ALLOCATED;

    pDMAGlobals->dmaChannelConfigInfo[dmaChannel].pDeviceHandler = dmaIntHandler;
    pDMAGlobals->dmaChannelConfigInfo[dmaChannel].pUserContext   = userContext;
    
    return XLLP_STATUS_SUCCESS;   
}
***/
    

//******************************************************************************
//
// Function Name: XllpDmacUnregisterDeviceHandler
//
// Description: Function called to unregister a previously registered handler 
//  			   
//  
// Input Arguments:
//		XLLP_UINT32_T		dmaChannel:     DMA channel
//	                 
// Output Arguments:
//  	
//
// Return Value: 
//	XLLP_ERR_BAD_CHANNEL:           When user passes an invalid DMA channel
//  XLLP_ERR_CHANNEL_NOT_ALLOCATED: When specified DMA chanel has not been allocated
//  XLLP_STATUS_SUCCESS:                  On success
//
// Notes:
//      Only one handler can be registered per DMA channel.
//      All interrupts for the specified DMA channel are disabled before unregistering
//      the handler
//      
//
//*******************************************************************************
// pkdebug ?? Function not needed.
/***
XLLP_STATUS_T	XllpDmacUnregisterDeviceHandler
(
	XLLP_DMAC_CHANNEL_T		dmaChannel	
)
{

    if(dmaChannel > XLLP_DMAC_CHANNEL_NUM)
	    return XLLP_ERR_BAD_CHANNEL;

	//
    //  Channel should be allocated before registering a handler
	//
    if (!pDMAGlobals->pArrayChannel[dmaChannel] )
        return XLLP_ERR_CHANNEL_NOT_ALLOCATED;

    XllpDmacDisableInterrupts( dmaChannel,	XLLP_ALL_INTERRUPTS_SOURCE);

    pDMAGlobals->dmaChannelConfigInfo[dmaChannel].pDeviceHandler = NULL;
    pDMAGlobals->dmaChannelConfigInfo[dmaChannel].pUserContext   = NULL;
    
    return XLLP_STATUS_SUCCESS;   
}
***/

//******************************************************************************
//
// Function Name: XllpDmacEnableInterrupts
//
// Description: Function called to enable specific interrupts related to specified DMA channel
//  			   
//  
// Input Arguments:
//		XLLP_UINT32_T		dmaChannel:         DMA channel
//		XLLP_UINT32_T		interruptBitmask:   Specified bitmask of interrupts to enable
//	                 
// Output Arguments:
//  	
//
// Return Value: 
//	XLLP_ERR_BAD_CHANNEL:           When user passes an invalid DMA channel
//  XLLP_ERR_NO_HANDLER:            When specified DMA chanel does not have a handler
//  XLLP_STATUS_SUCCESS:                  On success
//
// Notes:
//      A handler mut be registered for a DMA channel before interupts can be enabled
//      Only one handler can be registered per DMA channel.
//
//*******************************************************************************
// pkdebug. ?? Function not needed.
/***
XLLP_STATUS_T	XllpDmacEnableInterrupts
(
	XLLP_DMAC_CHANNEL_T	dmaChannel,	
	XLLP_UINT32_T		interruptBitmask
)
{    
    UINT32              intMask;

	//
	// Check for errors in DMA channel
	//
    if(dmaChannel > XLLP_DMAC_CHANNEL_NUM)
		return XLLP_ERR_BAD_CHANNEL;
    
	//
    //  Need a handler before enabling interrupts for channel.
	//
    if (!pDMAGlobals->dmaChannelConfigInfo[dmaChannel].pDeviceHandler)
        return XLLP_ERR_NO_HANDLER;   
        
	//
	// Enable the interrupts
	//    
    intMask     = pDmacHandle->DCSR[dmaChannel];
	intMask    |= interruptBitmask;
    pDmacHandle->DCSR[dmaChannel] = intMask;

    //RETAILMSG(1,(TEXT("DMA: EnableInt chan=%d DCSR=0x%08x \r\n"), dmaChannel, pDmacHandle->DCSR[dmaChannel] ));
    return XLLP_STATUS_SUCCESS;
}
***/

//******************************************************************************
//
// Function Name: XllpDmacDisableInterrupts
//
// Description: Function called to disable specific interrupts related to specified DMA channel
//  			   
//  
// Input Arguments:
//		XLLP_UINT32_T		dmaChannel:         DMA channel
//		XLLP_UINT32_T		interruptBitmask:   Specified bitmask of interrupts to disable
//	                 
// Output Arguments:
//  	
//
// Return Value: 
//	XLLP_ERR_BAD_CHANNEL:           When user passes an invalid DMA channel
//  XLLP_STATUS_SUCCESS:                  On success
//
// Notes:
//
//*******************************************************************************
// pkdebug ?? Function not needed.
/***
XLLP_STATUS_T    XllpDmacDisableInterrupts
(
	XLLP_DMAC_CHANNEL_T	dmaChannel,	
	XLLP_UINT32_T		interruptBitmask
)
{
    UINT32              intMask;

	//
	// Check for errors in DMA channel
	//
    if(dmaChannel > XLLP_DMAC_CHANNEL_NUM)
		return XLLP_ERR_BAD_CHANNEL;
    
	//
	// Disable the interrupts
	//
    intMask     = pDmacHandle->DCSR[dmaChannel];
	intMask  &= ~interruptBitmask;
    pDmacHandle->DCSR[dmaChannel] = intMask;	

    return XLLP_STATUS_SUCCESS;
}
***/

//******************************************************************************
//
// Function Name: XllpDmacGetRemainingXfrLength
//
// Description: Function called to retrieve remaining transfer length for specified 
//              DMA channel for currently attached descriptor
//  			   
//  
// Input Arguments:
//		XLLP_UINT32_T		dmaChannel:         DMA channel
//	                 
// Output Arguments:
//  	
//
// Return Value: 
//  XLLP_ERR_BAD_CHANNEL:           For out of range DMA channel
//	XLLP_INT32_T:                   Length remaining to be transferred for current descriptor
//
//
// Notes:
//
//
//*******************************************************************************
// pkdebug ?? Function not needed.
/***
XLLP_INT32_T	XllpDmacGetRemainingXfrLength
(
	XLLP_DMAC_CHANNEL_T	    dmaChannel	
)
{
	//
	// Check for errors in DMA channel
	//
    if(dmaChannel > XLLP_DMAC_CHANNEL_NUM)
		return XLLP_ERR_BAD_CHANNEL;
 
	//
	// Read the Descriptor Command register
	//    
    return (pDmacHandle->DDG[dmaChannel].DCMD & XLLP_DCMD_LEN_MASK);
}
***/


//******************************************************************************
//
// Function Name: XllpDmacCreateDescriptorListFromMdl
//
// Description: Creates a descriptor list for a buffer in virtual address space.
//  			   
//  
// Input Arguments:
//  PBufferMdl                  pBufferMdl:     Points to MDL for which desc list is to be created
//	XLLP_DMAC_TRANSFER_TYPE_T   transferType:   Specifies transfer type from/to device
//  XLLP_UINT32_T               deviceAddress:  Specfies device address from/to which DMA transfer will take place
//  XLLP_DMAC_COMMAND_T         pCmd:           Value for DCMD register
//	                 
// Output Arguments:
//  PDmaDescInfo  *pDmaDescInfo: Information baout DMA descriptors
//
// Return Value: 
//  XLLP_MEM_ALLOC_ERROR:       if error in allocating memory
//  XLLP_STATUS_SUCCESS:              when successful
//
//
// Notes:
//   The DMA descrptors returned are aligned on 16 byte boundaries
//
//*******************************************************************************
// pkdebug ?? Function not needed.
/***
XLLP_STATUS_T XllpDmacCreateDescriptorListFromMdl
(
    PBufferMdl                  pBufferMdl,
    XLLP_DMAC_TRANSFER_TYPE_T   transferType,
    PDmaDescInfo                *pDmaDescInfo,	
    XLLP_UINT32_T               deviceAddress,
    XLLP_DMAC_COMMAND_T         *pCmd
)
{
	XLLP_UINT32_T               i;
    XLLP_UINT32_T               sourceAddress;
    XLLP_UINT32_T               targetAddress;
    XLLP_UINT32_T               nextDescPhysicalAddress;
    XLLP_DMAC_DESC_ENABLE_T     aStopContinue;
    P_XLLP_DMAC_DESCRIPTOR_T    pLocalDmaDescList;
	
	*pDmaDescInfo = XllpDmacAllocDmaDescriptorList(pBufferMdl->numEntries);    

	if(! pDmaDescInfo)
		return XLLP_ERR_MEM_ALLOC;
    
    pLocalDmaDescList = (*pDmaDescInfo)->pDmaDescList;

	for(i=0;i<pBufferMdl->numEntries;++i)
	{
        //
        // Initialize the length
        //
		pCmd->aLen = ((XLLP_UINT16_T)pBufferMdl->physBlock[i].blockLength & XLLP_DCMD_LEN_MASK);

        //
        //
        //
        if (transferType == XLLP_DMAC_TRANSFER_MEM_TO_IO) 
        {
            sourceAddress = pBufferMdl->physBlock[i].physicalAds;
            targetAddress = deviceAddress;
        }
        else
        {
            sourceAddress = deviceAddress;
            targetAddress = pBufferMdl->physBlock[i].physicalAds;
        }

        //
        //
        //
        if (i == pBufferMdl->numEntries-1)
            nextDescPhysicalAddress = 0L;
        else
            nextDescPhysicalAddress = XllpDmacGetPhysicalAds((VOID*)&pLocalDmaDescList[i+1]);
            
        if (i == pBufferMdl->numEntries-1) 
            aStopContinue = XLLP_DMAC_DESC_STOP_CHANNEL; 
        else
            aStopContinue = XLLP_DMAC_DESC_RUN_CHANNEL;        
 
        //
        // Fill the DMA descriptor list for this buffer
        //
        XllpDmacFillLinkedDesc( &pLocalDmaDescList[i],
                                (P_XLLP_DMAC_DESCRIPTOR_T)nextDescPhysicalAddress,                                
                                aStopContinue,
                                XLLP_DMAC_DISABLE_DESC_BRANCH,
                                sourceAddress,
                                targetAddress,
                                pCmd );

    }
    
    return XLLP_STATUS_SUCCESS;
}
***/

//******************************************************************************
//
// Function Name: XllpDmacCreateDescriptorList
//
// Description: Creates a descriptor list for a buffer in virtual address space.
//  			   
//  
// Input Arguments:
//  PBufferMdl                  pBufferMdl:     Points to MDL for which desc list is to be created
//	XLLP_DMAC_TRANSFER_TYPE_T   transferType:   Specifies transfer type from/to device
//  XLLP_UINT32_T               deviceAddress:  Specfies device address from/to which DMA transfer will take place
//  XLLP_DMAC_COMMAND_T         pCmd:           Value for DCMD register
//	                 
// Output Arguments:
//  PDmaDescInfo  *pDmaDescInfo: Information baout DMA descriptors
//
// Return Value: 
//  XLLP_MEM_ALLOC_ERROR:       if error in allocating memory
//  XLLP_STATUS_SUCCESS:              when successful
//
//
// Notes:
//   The DMA descrptors returned are aligned on 16 byte boundaries
//
//*******************************************************************************
// pkdebug ?? Function not needed.
/***
XLLP_STATUS_T XllpDmacCreateDescriptorList
(
    XLLP_UINT8_T*               pBuffer,
    XLLP_UINT32_T               bufferLength,
    XLLP_DMAC_TRANSFER_TYPE_T   transferType,
    PDmaDescInfo                *pDmaDescInfo,	
    XLLP_UINT32_T               deviceAddress,
    XLLP_DMAC_COMMAND_T         *pCmd,
    XLLP_DMAC_ALIGNMENT_T*      aLign
)
{
    PBufferMdl                  pBufferMdl;
    XLLP_STATUS_T               status;
	
    //
    // Create a MDL for the buffer
    //
    status = XllpDmacCreateBufferMdl(pBuffer, bufferLength, &pBufferMdl, aLign);
    if (status != XLLP_STATUS_SUCCESS)
        return status;

    //
    // Create the DMA descriptor list for this buffer
    //
    status = XllpDmacCreateDescriptorListFromMdl(pBufferMdl, transferType, pDmaDescInfo, deviceAddress, pCmd);
    
    //
    // Free the buffer MDL since we dont need it anymore
    //
    XllpDmacFreeBufferMdl(pBuffer, bufferLength, pBufferMdl);
		
    return status;
}
***/


//******************************************************************************
//
// Function Name: XllpDmacChainDescriptors
//
// Description: Chains descriptors for back to back DMA transfers
//  			   
//  
// Input Arguments:
//   pCurrentDmaDesc:       Current DMA descriptor
//   pNextDmaDesc           Next DMA descriptor to be inserted in chain
//	                 
// Output Arguments:
//
//
// Return Value: 
//  descPhysicalAddress: Physical address of next descriptor...should be non 0
//
// Notes:
//   The DMA descrptors must be aligned on 16 byte physical boundaries
//
//*******************************************************************************
XLLP_UINT32_T XllpDmacChainDescriptors
(
    P_XLLP_DMAC_DESCRIPTOR_T    pCurrentDmaDesc,
    P_XLLP_DMAC_DESCRIPTOR_T    pNextDmaDesc
)
{
    XLLP_UINT32_T   descPhysicalAddress;

    descPhysicalAddress = XllpDmacGetPhysicalAds((VOID*)pNextDmaDesc);
    pCurrentDmaDesc->ddadr = descPhysicalAddress;
    return descPhysicalAddress;
}


//******************************************************************************
//
// Function Name: XllpDmacAllocateMdl
//
// Description: Allocates a memory descriptor list.
//  			   
//  
// Input Arguments:
//  numEntries:     Number of physical block entries in the MDL
//	                 
// Output Arguments:
//
//
// Return Value: 
//  PBufferMdl:     The allocated MDL pointer
//
//
// Notes:
//
//
//*******************************************************************************
PBufferMdl XllpDmacAllocateMdl
(
    XLLP_UINT32_T	numEntries
)
{
    XLLP_UINT32_T   memSize;
    PBufferMdl      pBufferMdl;

    memSize = sizeof(BufferMdl) + (numEntries * sizeof(PhysBlock));
    pBufferMdl = (PBufferMdl) OSMemAlloc(memSize);
    if(pBufferMdl)	
        pBufferMdl->physBlock = (PhysBlock*) ((XLLP_UINT32_T)pBufferMdl + sizeof(BufferMdl));
	
    return pBufferMdl;
}

//******************************************************************************
//
// Function Name: XllpDmacFreeBufferMdl
//
// Description: Frees a MDL allocated for a buffer.
//  			   
//  
// Input Arguments:
//  pBuffer:        Pointer to buffer
//  bufferLength;   length of buffer
//  pBufferMdl:     Pointer to memory descriptor list which needs to be freed
//
//	                 
// Output Arguments:
//
//
// Return Value: 
//
// Notes:
//  The buffer is unlocked in physical memory and then freed
//
//*******************************************************************************
void XllpDmacFreeBufferMdl
(
	XLLP_UINT8_T    *pBuffer,
	XLLP_UINT32_T	bufferLength,
	PBufferMdl      pBufferMdl
)
{
	OSUnlockPhysicalPages(pBuffer, bufferLength);
	OSMemFree(pBufferMdl);
	return;
}

//******************************************************************************
//
// Function Name: XllpDmacGetPhysicalAds
//
// Description: Retrieves the physical address for any specified virtual address
//  			   
//  
// Input Arguments:
//  virtualAddress:        Virtual Address 
//	                 
// Output Arguments:
//
// Return Value: 
//  0:                      Error in retrieving physical address
//  physicalAddress:        Physical address of start of buffer
//
// Notes:
//  The buffer is not locked in physical memory.
//
//*******************************************************************************
XLLP_UINT32_T XllpDmacGetPhysicalAds
(
	VOID*	virtualAddress	
)
{
    BOOL            fResult;
    XLLP_UINT32_T   pageAddress;
    XLLP_UINT32_T   pageOffset;
	//
	// Query address of first page occupied by this buffer
	//
	fResult = OSLockPhysicalPages(virtualAddress, 0x1L, &pageAddress, LOCKFLAG_QUERY_ONLY);
	if (!fResult)
		return 0;

    //
    // Calculate the offset into the page and add it to the page address
    //
    pageOffset = ((XLLP_UINT32_T)virtualAddress & (PAGE_SIZE-1));
    return (pageAddress + pageOffset);	
}

//******************************************************************************
//
// Function Name: XllpDmacCreateBufferMdl
//
// Description: Creates a Memory Descriptor List (MDL) for the user buffer.
//  			   
//  
// Input Arguments:
//  pBuffer:        Pointer to buffer
//  bufferLength;   length of buffer
//	                 
// Output Arguments:
//  pBufferMdl:     Pointer to memory descriptor list which is returned to caller
//  aLign:          Flag which describes if buffer is aligned on 8 byte boundary or not
//
// Return Value: 
//  XLLP_ERR_MEM_ALLOC: Error in memory allocation
//  XLLP_STATUS_SUCCESS:      hen successful
//
// Notes:
//  The caller is responsible for freeing memory occupied by the MDL.
//  The max size of each physically contigious block in the MDL list is restricted to 4K,
//  since maximum permitted transfer anyway is 8K-1 (less than two pages) bytes.
//
//*******************************************************************************
// pkdebug ?? Function not needed.
/***
XLLP_STATUS_T XllpDmacCreateBufferMdl
(
    XLLP_UINT8_T            *pBuffer,
    XLLP_UINT32_T           bufferLength,
    PBufferMdl              *pBufferMdl,
    XLLP_DMAC_ALIGNMENT_T   *aLign
)
{

    XLLP_UINT32_T   i;
    XLLP_UINT32_T   maxPages;
	XLLP_UINT32_T   *aPages;
	BOOL            fResult;
	XLLP_UINT32_T   firstPageOffset;
	XLLP_UINT32_T   lastPageOffset;
    XLLP_STATUS_T   status=XLLP_STATUS_SUCCESS;

	//
	// In case there are errors, that's what we shall return
	//
	*pBufferMdl = NULL;

    if(!pBuffer)
		return XLLP_ERR_MEM_ALLOC;
    
	//
	// Find maximum number of pages that can be occupied by this buffer
	//
	maxPages = OSGetMaxPages(pBuffer, bufferLength);
	aPages = (XLLP_UINT32_T*) OSMemAlloc( maxPages*sizeof(XLLP_UINT32_T));
	if(!aPages)
		return XLLP_ERR_MEM_ALLOC;

	//
	// Get list of all physical pages occupied by this buffer
	//
	fResult = OSLockPhysicalPages(pBuffer, bufferLength, aPages, LOCKFLAG_WRITE);
	if (!fResult)
    {
        RETAILMSG(1,(TEXT("DMA:>XllpDmacCreateBufferMdl Error..\r\n")));
        status = XLLP_ERR_MEM_ALLOC;
		goto Label_CreateBufferMdl;			 
    }

	//
	// Allocate space for MDL for the number of entries we calculated above
	//
    if( (*pBufferMdl = XllpDmacAllocateMdl(maxPages)) == NULL)
	{
		fResult = XLLP_ERR_MEM_ALLOC;
		goto Label_CreateBufferMdl;
	}

	//
	// Initialize entries in the MDL
	// The buffer can be starting from middle of a page and also ending in middle of a page
	//
	firstPageOffset					= ((XLLP_UINT32_T)pBuffer & (PAGE_SIZE-1));
	lastPageOffset					= (((XLLP_UINT32_T)pBuffer + bufferLength) & (PAGE_SIZE-1));
	(*pBufferMdl)->numEntries		= maxPages;
	(*pBufferMdl)->bufferPtr		= pBuffer;

	//
	// Add the starting page offset for the first physical block
	// Set the length to buffer length for default case of no page breaks in between
	// If there are page breaks, then the length will get adjusted below.
	//
	(*pBufferMdl)->physBlock[0].physicalAds	= (aPages[0] + firstPageOffset);
	(*pBufferMdl)->physBlock[0].blockLength	= bufferLength;
		
	if(maxPages > 1)
	{
		//
		// Since there are page breaks, set the size of first block to only the size on first page
		//		
		(*pBufferMdl)->physBlock[0].blockLength = (PAGE_SIZE - firstPageOffset);
		for(i=1; i<maxPages-1; ++i)
		{			
			//
			// We got a page break
			// Set the starting address of next block
			// Initialize the size of next physical block to PAGE_SIZE
			//		
			(*pBufferMdl)->physBlock[i].physicalAds = aPages[i];
			(*pBufferMdl)->physBlock[i].blockLength = PAGE_SIZE;			
		}

		//
		// Adjust the size of last block with the last page offset in case the 
		// buffer ends in middle of a page
		//
		(*pBufferMdl)->physBlock[i].physicalAds		= aPages[i];			
		(*pBufferMdl)->physBlock[i].blockLength		= lastPageOffset == 0 ? PAGE_SIZE : lastPageOffset;
	}   
   	
    //
    // If physical address of any of the blocks does not start at 8 byte boundary we may
    // need to turn on the alignment flag
    //
    *aLign = XLLP_DMAC_ALIGNMENT_OFF;
    for(i=1; i<maxPages-1; ++i)
        if ((*pBufferMdl)->physBlock[i].physicalAds & 0x7)
            *aLign = XLLP_DMAC_ALIGNMENT_ON;

Label_CreateBufferMdl:
	OSMemFree(aPages);

	return XLLP_STATUS_SUCCESS;
}
***/


//******************************************************************************
//
// Function Name: XllpDmacAllocDmaDescriptorList
//
// Description: Allocates a DMA descriptor list for the buffer
//  			   
//  
// Input Arguments:
//  numEntries:     Number of descriptor entries for which space needs to be allocated
//                
// Output Arguments:
//
// Return Value: 
//  pDmaDescInfo:   Pointer to structure which contains information about allocated
//                  DMA descriptors.
//
// Notes:
//  The allocated DMA descriptors will be aligned on 16 byte physical boundaries
//
//*******************************************************************************
PDmaDescInfo  XllpDmacAllocDmaDescriptorList
(
	XLLP_UINT32_T		numEntries
)
{
    XLLP_UINT32_T       memSize;
    XLLP_UINT32_T       descAlignOffset;    
    PDmaDescInfo        pDmaDescInfo;

    //
    // Allocate an extra descriptor so that we can align the decriptors appropriately
    // The DMA descriptors need to be aligned on 16 byte boundaries.
    //
    memSize = sizeof(DmaDescInfo) + ((numEntries + 1) * sizeof(XLLP_DMAC_DESCRIPTOR_T));              
       
    pDmaDescInfo = (PDmaDescInfo) OSMemAlloc( memSize );
    if(pDmaDescInfo)
    {
        pDmaDescInfo->memPtr        = (XLLP_UINT8_T*)pDmaDescInfo;
        pDmaDescInfo->numEntries    = numEntries;
        descAlignOffset             = (XLLP_UINT32_T)pDmaDescInfo + sizeof(DmaDescInfo) + 
                                       sizeof(XLLP_DMAC_DESCRIPTOR_T);
        descAlignOffset             &= XLLP_DMAC_ALIGN_MASK;
        pDmaDescInfo->pDmaDescList  = (P_XLLP_DMAC_DESCRIPTOR_T) descAlignOffset;
    }

	return (pDmaDescInfo);
}

//******************************************************************************
//
// Function Name: XllpDmacFreeDescriptorList
//
// Description: Frees a previously allocated DMA descriptor list for the buffer
//  			   
//  
// Input Arguments:
//  pDmaDescInfo:   Pointer to structure which contains information about allocated
//                  DMA descriptors.
//	                 
// Output Arguments:
//
// Return Value: 
//
// Notes:
//
//
//*******************************************************************************
VOID  XllpDmacFreeDescriptorList
(
	PDmaDescInfo        pDmaDescInfo
)
{         
    OSMemFree( pDmaDescInfo->memPtr );    
}

//******************************************************************************
//
// Function Name: XllpDmacGetXfrDone
//
// Description: Gets the number of bytes transferred for a particular descriptor
//  			list   
//  
// Input Arguments:
//
//	                 
// Output Arguments:
//
// Return Value: 
//
// Notes:
//
//
//*******************************************************************************
// pkdebug ?? Function not needed.
/***
XLLP_STATUS_T XllpDmacGetXfrDone
(
    XLLP_DMAC_CHANNEL_T             dmaChannel,    
    PBufferMdl                      pBufferMdl,
    XLLP_DMAC_TRANSFER_TYPE_T       transferType,
    XLLP_UINT32_T                   *bytesXferred
)
{

    XLLP_UINT32_T       currAddress;
    XLLP_UINT32_T       i;
    XLLP_UINT32_T       bytesDone=0;
    XLLP_UINT32_T       bytesRem=0;
    PPhysBlock          pPhys=pBufferMdl->physBlock;
    *bytesXferred = 0;
   
    if(transferType==XLLP_DMAC_TRANSFER_IO_TO_MEM)    
        currAddress = pDmacHandle->ddg[dmaChannel].dtadr;            
    else
        currAddress = pDmacHandle->ddg[dmaChannel].dsadr;        

    for(i=0;i<pBufferMdl->numEntries;++i)
    {
        bytesDone += pPhys[i].blockLength;
        if(currAddress >= pPhys[i].physicalAds && 
           currAddress <= pPhys[i].physicalAds + pPhys[i].blockLength )
           break;        
    }

    if(i==pBufferMdl->numEntries)
    {
        RETAILMSG(1,(TEXT("DMA:>XllpDmacGetXfrDone bad Mdl. dmaChan=%d \r\n"), dmaChannel ));
        return XLLP_ERR_BAD_MDL;
    }

    bytesRem        = XllpDmacGetRemainingXfrLength(dmaChannel);
    bytesDone      -= bytesRem;
    *bytesXferred   = bytesDone;

    RETAILMSG(1,(TEXT("DMA:>XllpDmacGetXfrDone dmaChan=%d bytesDone=%d curAds=0x%08x \r\n"), dmaChannel, bytesDone, currAddress));
    return XLLP_STATUS_SUCCESS;
}
***/


//******************************************************************************
//
// Function Name: XllpDmacSetupTransfer
//
// Description: Sets up a complete transfer operation
//  
// Input Arguments:
//  aChannelPriority    DMA channel priority
//  pUserBuffer         Pointer to user buffer
//  xferByteCount       Number of bytes to be transferred
//  transferType        Transfer type
//  deviceAddress       Address on device. This can be 4 byte aligned
//  aDeviceDrcmr        Device DRCMR for mapping the DMA Channel
//  dmaIntHandler       DMA interrupt handle to be called on completion or errors
//  pUserContext        User context to be passed back in callback
//  intEnableBitmask    Bitmask of interrupts that can be enabled during the transfer
//  descBasedXfr        Descriptor based transfer or not.
//  pCmd                Pointer to value of DCMD register for current operation
//
//	                 
// Output Arguments:
//    dmaChannel        DMA channel allocated for current operation
//    pUserDmaDescInfo  UserDMA descriptor information
//    pUserBufferMdl    Mdl decribing the user buffer
//
// Return Value: 
//      XLLP_STATUS_SUCCESS:  on success
//
// Notes: This is a workhorse routine which sets up either descriptor based
//        or non-descriptor based transfer operation.  
//
//*******************************************************************************
// pkdebug.  ?? Function not needed.
/***
XLLP_STATUS_T XllpDmacSetupTransfer
(    
    XLLP_DMAC_CHANNEL_PRIORITY_T    aChannelPriority,
    XLLP_UINT8_T*                   pUserBuffer,
    XLLP_UINT32_T                   xferByteCount,
    XLLP_DMAC_TRANSFER_TYPE_T       transferType,
    XLLP_UINT32_T                   deviceAddress,
    XLLP_DMAC_DEVICE_T              aDeviceDrcmr,
    DeviceDmaIntHandler             dmaIntHandler,
    PVOID                           pUserContext,
    XLLP_UINT32_T                   intEnableBitmask,
    XLLP_UINT32_T                   descBasedXfr,
    XLLP_DMAC_COMMAND_T*            pCmd,
    XLLP_DMAC_CHANNEL_T*            dmaChannel,
    PDmaDescInfo*                   pUserDmaDescInfo,
    PBufferMdl*                     pUserBufferMdl
)
{

    XLLP_STATUS_T           status;
    XLLP_DMAC_CHANNEL_T     aChannel=XLLP_INVALID_DMA_CHANNEL;
    PBufferMdl              pBufferMdl=NULL;
    PDmaDescInfo            pDmaDescInfo=NULL;
    XLLP_DMAC_ALIGNMENT_T   aLign=XLLP_DMAC_ALIGNMENT_ON;
    XLLP_UINT32_T           physAds;
    
    physAds = XllpDmacGetPhysicalAds(pUserBuffer);  
    //RETAILMSG(1,(TEXT("DMA: XllpDmacSetupTransfer physAds=0x%08x devAds=0x%08x \r\n"), physAds, deviceAddress));    

    //
    // Allocate a DMA channel based on specified user priority
    //
    status = XllpDmacAllocChannel(&aChannel, aChannelPriority );
    if (status != XLLP_STATUS_SUCCESS)
        return status;

    //
    // Register a handler for the allocated DMA channel
    //
    *dmaChannel = (UINT32)(aChannel);
    status = XllpDmacRegisterDeviceHandler(aChannel, dmaIntHandler,pUserContext);
    if (status != XLLP_STATUS_SUCCESS)
        goto Label_CleanSetupDmacTransfer;


    if(descBasedXfr)
    {
        //
        // Create a MDL for the buffer
        //
        status = XllpDmacCreateBufferMdl(pUserBuffer, xferByteCount, &pBufferMdl, &aLign);
        if (status != XLLP_STATUS_SUCCESS)
            goto Label_CleanSetupDmacTransfer;

        //
        // Create the DMA descriptor list for this buffer
        //
        status = XllpDmacCreateDescriptorListFromMdl(pBufferMdl, 
                                                     transferType, 
                                                     &pDmaDescInfo, 
                                                     deviceAddress, 
                                                     pCmd);
    


        if (status != XLLP_STATUS_SUCCESS)
            goto Label_CleanSetupDmacTransfer;
 	
        //
        // Load the DMA descriptors into the DMA registers
        //
        XllpDmacCfgChannelDescTransfer((XLLP_DMAC_DESCRIPTOR_T*)XllpDmacGetPhysicalAds((void*) pDmaDescInfo->pDmaDescList), 
                                       aChannel, 
                                       aDeviceDrcmr, 
                                       aLign);

        //
        // Just need to call XllpDmacStartTransfer to initiate transfer at this point
        // Return the DMA descriptor information, since the user will have to free this later on
        //
        *pUserDmaDescInfo = pDmaDescInfo;        
        *pUserBufferMdl   = pBufferMdl;
    }    

    if(!descBasedXfr)
    {
        XllpDmacCfgChannelNoDescTransfer(((transferType==XLLP_DMAC_TRANSFER_IO_TO_MEM) ? deviceAddress : physAds),
		    				  			 ((transferType==XLLP_DMAC_TRANSFER_IO_TO_MEM) ? physAds : deviceAddress),
			    			  			 pCmd,
                                         aChannel,
                                         aDeviceDrcmr, 
                                         aLign);
    }

    //
    // Enable specified interrupts for the DMA channel
    //    
    status = XllpDmacEnableInterrupts(aChannel, intEnableBitmask);
    if (status != XLLP_STATUS_SUCCESS)
        goto Label_CleanSetupDmacTransfer;

    //
    // Just need to call XllpDmacStartTransfer to initiate transfer at this point    
    //
    return XLLP_STATUS_SUCCESS;
    
Label_CleanSetupDmacTransfer:

    if(pBufferMdl)
        XllpDmacFreeBufferMdl(pUserBuffer, xferByteCount, pBufferMdl);

    if (pDmaDescInfo)
        XllpDmacFreeDescriptorList(pDmaDescInfo);

    if (aChannel != XLLP_INVALID_DMA_CHANNEL)
    {
        XllpDmacDisableInterrupts(aChannel, XLLP_ALL_INTERRUPTS_SOURCE);
        XllpDmacUnregisterDeviceHandler(aChannel);  
        XllpDmacFreeChannel(aChannel, aDeviceDrcmr);
    }

    return status;
}
***/
